#include "cppTutorTypeCasting.h"

/////////////////////
//      CBase      //
/////////////////////
CBase :: CBase () : m_nBase (0) {
    Log << "ENTER : CBase :: CBase " << endl;
    Log << "EXIT  : CBase :: CBase " << endl;       
}
    
CBase :: ~CBase () {
    Log << "ENTER : CBase :: ~CBase " << endl;
    Log << "EXIT  : CBase :: ~CBase " << endl;
}
        
void CBase :: m_Test () {
    Log << "ENTER : CBase :: m_Test " << endl;
    cout << "CBase :: m_Test ()" << endl;
    Log << "EXIT  : CBase :: m_Test " << endl;
}

/////////////////////
//   CDerived      //
/////////////////////
CDerived :: CDerived () : m_nDerived (0) {
    Log << "ENTER : CDerived :: CDerived " << endl;
    Log << "EXIT  : CDerived :: CDerived " << endl;   
}

CDerived :: ~CDerived () {
    Log << "ENTER : CDerived :: ~CDerived " << endl;
    Log << "EXIT  : CDerived :: ~CDerived " << endl; 
}

void CDerived :: m_Test () {
    Log << "ENTER : CDerived :: m_Test " << endl;
    cout << "CDerived :: m_Test ()" << endl;
    Log << "EXIT  : CDerived :: m_Test " << endl;
}

///////////////////////////
// CcppTutorTypeCasting  //
///////////////////////////     
CcppTutorTypeCasting :: CcppTutorTypeCasting ()
{
    Log << "ENTER : CcppTutorTypeCasting :: CcppTutorTypeCasting" << endl;
    Log << "EXIT  : CcppTutorTypeCasting :: CcppTutorTypeCasting" << endl;
}

CcppTutorTypeCasting :: ~CcppTutorTypeCasting ()
{
    Log << "ENTER : CcppTutorTypeCasting :: ~CcppTutorTypeCasting" << endl;
    Log << "EXIT  : CcppTutorTypeCasting :: ~CcppTutorTypeCasting" << endl;
}

void CcppTutorTypeCasting :: m_StaticCast ()
{
    Log << "ENTER : CcppTutorTypeCasting :: m_StaticCast" << endl;
    try {    
        CStandalone* psSC;
        CStandalone sSC;
        CBase* pbSC;
        CDerived* pdSC;
        CDerived dSC;		
        CBase bSC;

        pbSC = static_cast <CBase*> (&dSC);
        
        int i = 0x7fff; // Max pos value = 32767
        long l;
        float f;

        // (1) Typical castless conversions:
        //l = i;
        //f = i;

        //cout << "l = i; l = " << l << endl;
        //cout << "f = i; f = " << f << endl;

        // Also works:
        l = static_cast<long>(i);
        f = static_cast<float>(i);

        cout << "l = static_cast<long> (i); l = " << l << endl;
        cout << "f = static_cast<float>(i); f = " << f << endl;

        // (2) Narrowing conversions:
        //i = l; // May lose digits
        //cout << "i = l; i = " << i << endl;
        //i = f; // May lose info
        //cout << "i = f; i = " << i << endl;

        // Says "I know," eliminates warnings:
        i = static_cast<int>(l);
        cout << "i = static_cast<int>(l); i = " << i << endl;
        i = static_cast<int>(f);
        cout << "i = static_cast<int>(f); i = " << i << endl;
        char c = static_cast<char>(i);
        cout << c;
        // (3) Forcing a conversion from void* :
        void* vp = &i;
        cout << "void* vp = &i; vp = " << vp << endl;

        // Old way produces a dangerous conversion:
        float* fp = (float*)vp;
        cout << "float* fp = (float*)vp; fp = " << fp << endl;

        // The new way is equally dangerous:
        fp = static_cast<float*>(vp);

        // (4) Implicit type conversions, normally
        // performed by the compiler:
        double d = 0.0;
        int x;
        //x = d; // Automatic type conversion
        //cout << "int x = d; d = " << d << endl;

        x = static_cast<int>(d); // More explicit
        cout << "x = static_cast<int>(d); d = " << d << endl;

        //func(d); // Automatic type conversion
        func(static_cast<int>(d)); // More explicit
    }
    catch (exception& e) {
        cout << "Exception: " << e.what();
    }    
    Log << "EXIT  : CcppTutorTypeCasting :: m_StaticCast" << endl;
}

void CcppTutorTypeCasting :: m_ConstCast ()
{
    Log << "ENTER : CcppTutorTypeCasting :: m_ConstCast" << endl;
    const int nX = 10;
    // deprecated form
    int *nY = (int*)&nX;
    cout << *nY << endl;

    int *nZ = const_cast<int*>(&nX);
    cout << *nZ << endl;
    
    Log << "EXIT  : CcppTutorTypeCasting :: m_ConstCast" << endl;
}

void CcppTutorTypeCasting :: m_DynamicCast () {
    Log << "ENTER : CcppTutorTypeCasting :: m_DynamicCast" << endl;
    try {
        // CStandalone* ps;
        // CStandalone s;
        CBase* pb;
        CDerived* pd;
        CDerived d;		
        CBase b;    
        CBase * pba = new CDerived;
        CBase * pbb = new CBase;
        
        pb = dynamic_cast <CBase*> (&d);     // ok: derived-to-base
        if (pb == NULL) {
            cout << "Dynamic Cast failed from derived to base conversion" << endl;
        }
        else {
            cout << "Conversion  : [pb = dynamic_cast <CBase*> (&d)] success" << endl;
        }
        
        //
        // dynamic_cast unsuccessful here, when converting base to its derived
        //  
        pd = dynamic_cast <CDerived*> (&b);
        if (pd == NULL) {
            cout << "Dynamic Cast failed from base to derived conversion" << endl;
        }
        else {
            cout << "Conversion  : [pd = dynamic_cast <CDerived*> (&b)] success" << endl;
        }

        pd = dynamic_cast<CDerived*>(pba);
        if (pd == 0) {
            cout << "Conversion  : [pd = dynamic_cast<CDerived*>(pba)] fails" << endl;
            cout << "Null pointer on first type-cast" << endl;
        }

        pd = dynamic_cast<CDerived*>(pbb);
        if (pd == 0) {
            cout << "Null pointer on second type-cast" << endl;
        }
        else {
            cout << "Conversion  : [pd = dynamic_cast<CDerived*>(pbb)] fails" << endl;
        }
        
        //cppTutorTypeCasting.cpp:172: error: cannot dynamic_cast ((CcppTutorTypeCasting*)this)->CcppTutorTypeCasting::ps (of type class CStandalone*) to type class CBase* (source type is not polymorphic)
        // cout << "Casting unrelated class using dynamic_cast" << endl;
        // pb = dynamic_cast <CBase*> (ps);
        
        delete pba;
        delete pbb;
    }
    catch (exception& e) {
        cout << "Exception: " << e.what();
    }
    Log << "EXIT  : CcppTutorTypeCasting :: m_DynamicCast" << endl;
}
